package xyz.jcat.web.security.annotation;

import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.core.Authentication;
import xyz.jcat.common.util.CollectionUtils;
import xyz.jcat.common.web.RespCodeMsg;
import xyz.jcat.common.web.RespException;
import xyz.jcat.security.UserRoleAuthenticationToken;

import java.util.Collection;
import java.util.Iterator;
import java.util.List;

/**
 * 权限注解权限校验器
 * 根据配置的权限标识查询需要的角色id进行权限验证
 */
public abstract class AbstractAuthAnnotationAccessDecisionVoter implements AccessDecisionVoter {

    @Override
    public boolean supports(ConfigAttribute attribute) {
        return attribute instanceof SecurityConfig;
    }

    @Override
    public int vote(Authentication authentication, Object object, Collection collection) {
        Iterator iterator = collection.iterator();
        SecurityConfig securityConfig;
        if(iterator.hasNext()) {
            securityConfig = (SecurityConfig)iterator.next();
        }else {
            return ACCESS_GRANTED;
        }
        String permission = securityConfig.getAttribute();
        if(PermissionSecurityConfig.loginOnly(permission)) {
            return ACCESS_GRANTED;
        }
        List<Long> roleIds = getPermissionRoles(permission);
        //不需要role
        if(CollectionUtils.isEmpty(roleIds)) {
            return ACCESS_GRANTED;
        }
        UserRoleAuthenticationToken userRoleAuthenticationToken = (UserRoleAuthenticationToken) authentication;
        List<Long> userRoleIds = userRoleAuthenticationToken.getRoleIds();
        if(CollectionUtils.isEmpty(userRoleIds)) {
            throw new RespException(RespCodeMsg.FORBIDDEN);
        }
        for (Long userRoleId : userRoleIds) {
            if(roleIds.contains(userRoleId)) {
                return ACCESS_GRANTED;
            }
        }
        throw new RespException(RespCodeMsg.FORBIDDEN);
    }

    @Override
    public boolean supports(Class clazz) {
        return true;
    }

    public abstract List<Long> getPermissionRoles(String permission);
}
